package com.hxkj.service.impl;

import com.hxkj.dao.UserDao;
import com.hxkj.domain.enums.UserExceptionEnum;
import com.hxkj.domain.po.IncrementSequence;
import com.hxkj.domain.po.LoginToken;
import com.hxkj.domain.po.SysUser;
import com.hxkj.service.IncrementSequenceService;
import com.hxkj.service.UserService;
import com.hxkj.token.TokenGenerator;
import com.hxkj.utils.AESUtil;
import com.hxkj.utils.MD5Utils;
import com.platform.common.domain.exception.CustomException;
import com.platform.common.domain.result.ResultDataStruct;
import com.platform.common.domain.result.ResultMessageStruct;
import com.platform.common.service.sftp.domain.annotation.FormatUrl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.Objects;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * created by kezhijie on 2018/8/21 9:35.
 * email to kezhijie@hxoss.com
 */
@Service
@Slf4j
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDao userDao;

    @Autowired
    private TokenGenerator tokenGenerator;

    @Autowired
    private IncrementSequenceService incrementSequenceService;

    /*
     这里可以优先考虑动态插入，毕竟有些字段是需要前段做控制，而非后台做控制的 kezhijie 20180821
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @FormatUrl
    public ResultMessageStruct save(SysUser sysUser) throws Exception {
        ResultMessageStruct resultMessageStruct = new ResultMessageStruct();

        // basic validate
        if(StringUtils.isEmpty(sysUser.getPassword())) {
            throw new CustomException(UserExceptionEnum.USER_PASSWORD_NOT_NULL);
        }

        if (sysUser.getPassword().length() > 20 || sysUser.getPassword().length() < 6)
            throw new CustomException(UserExceptionEnum.PASSWORD_LENGTH_LIMIT);
        if (isNumeric(sysUser.getPassword()) || !isContainNum(sysUser.getPassword()))
            throw new CustomException(UserExceptionEnum.PASSWORD_LENGTH_LIMIT);

        // 检查用户是否已经存在
        SysUser exists = userDao.findExists(sysUser);

        if (Objects.nonNull(exists)) {
            resultMessageStruct.setCode(UserExceptionEnum.USER_ARE_EXIST.getCode());
            resultMessageStruct.setMessage(UserExceptionEnum.USER_ARE_EXIST.getMsg());
        } else {

            if (StringUtils.isEmpty(sysUser.getUserAccount()))
                sysUser.setUserAccount(constructUsername());

            int i = userDao.saveSelective(sysUser);
            if (i > 0) {
                resultMessageStruct.setCode(200);
                resultMessageStruct.setMessage("用户添加成功");
            } else {
                resultMessageStruct.setCode(500);
                resultMessageStruct.setMessage("用户添加失败，请核对信息后重试");
            }
        }
        return resultMessageStruct;
    }

    @Override
    public ResultDataStruct<LoginToken>  login(SysUser sysUser) throws Exception {

        ResultDataStruct resultMessage = new ResultDataStruct();

        // assert username or password is not null
        if (StringUtils.isEmpty(sysUser.getUserAccount()) || StringUtils.isEmpty(sysUser.getPassword())) {

            resultMessage.setCode(UserExceptionEnum.USER_ACCOUNT_IS_NULL.getCode());
            resultMessage.setMessage(UserExceptionEnum.USER_ACCOUNT_IS_NULL.getMsg());

            return resultMessage;

        }

        String password = sysUser.getPassword();



        SysUser existsSysUser = userDao.findExists(sysUser);


        if (Objects.nonNull(existsSysUser)) {

            // 用户被禁用
            if (existsSysUser.getDelTag().equals("1")) {
                resultMessage.setCode(UserExceptionEnum.USER_LIMIT.getCode());
                resultMessage.setMessage(UserExceptionEnum.USER_LIMIT.getMsg());
                return resultMessage;
            }

            // 用户未激活
            if (existsSysUser.getUserStatus().toString().equals("1")) {
                resultMessage.setCode(UserExceptionEnum.USER_NOT_ACTIVE.getCode());
                resultMessage.setMessage(UserExceptionEnum.USER_NOT_ACTIVE.getMsg());
                return resultMessage;
            }

            // 密码加盐值验证
            boolean verification = MD5Utils.validPassword(password, existsSysUser.getPassword(), existsSysUser.getSalt());

            if (verification) {
                LoginToken loginToken = tokenGenerator.generatorLoginToken(null, sysUser.getUserAccount(), existsSysUser.getUserId());

                resultMessage.setCode(200);
                resultMessage.setMessage("成功");
                resultMessage.setData(loginToken);

                log.debug("用户 {} 登录成功", existsSysUser);
            } else {
                resultMessage.setCode(UserExceptionEnum.ACCOUNT_ERROR.getCode());
                resultMessage.setMessage(UserExceptionEnum.ACCOUNT_ERROR.getMsg());
            }

        } else {
            resultMessage.setCode(UserExceptionEnum.USER_NOT_EXIST.getCode());
            resultMessage.setMessage(UserExceptionEnum.USER_NOT_EXIST.getMsg());
        }

        return resultMessage;
    }

    @Override
    @FormatUrl(type = "after")
    public SysUser existsUser(SysUser condition) throws Exception {
        return userDao.findExists(condition);
    }

    @Override
    @FormatUrl
    @Transactional(rollbackFor = Exception.class)
    public ResultDataStruct<SysUser> update(SysUser sysUser) throws Exception {

        ResultDataStruct<SysUser> resultDataStruct = new ResultDataStruct<>();

        if (Objects.isNull(sysUser) || StringUtils.isEmpty(sysUser.getUserId())) {
            resultDataStruct.setCode(UserExceptionEnum.USERINFO_INVALID.getCode());
            resultDataStruct.setMessage(UserExceptionEnum.USERINFO_INVALID.getMsg());
            return resultDataStruct;
        }

        try {

            SysUser dbUser = userDao.findByUserId(sysUser.getUserId());

            if (StringUtils.hasText(sysUser.getEmail()) && StringUtils.hasText(dbUser.getEmail()) && !(dbUser.getEmail().equals(sysUser.getEmail()))){
                SysUser condition = new SysUser();
                condition.setEmail(sysUser.getEmail());
                SysUser exists = userDao.findExists(condition);
                if (Objects.nonNull(exists))
                    throw new CustomException(UserExceptionEnum.EMAIL_BE_USED);
            }


            if (StringUtils.hasText(sysUser.getUserAccount()) && Objects.nonNull(dbUser) && !dbUser.getUserAccount().equals(sysUser.getUserAccount())){
                userDao.updateUserAccount(sysUser);
            }

            if (StringUtils.hasText(sysUser.getPhone()))
                userDao.updatePhone(sysUser);

            int i = userDao.updateSelectiveExcludePassword(sysUser);
            if (i > 0) {
                resultDataStruct.setCode(200);
                resultDataStruct.setMessage("修改成功");
                resultDataStruct.setData(userDao.findByUserId(sysUser.getUserId()));
            } else {
                resultDataStruct.setCode(500);
                resultDataStruct.setMessage("修改失败，请核对信息后重试");
            }

        } catch (CustomException e) {
            resultDataStruct.setCode(e.getCode().getCode());
            resultDataStruct.setMessage(e.getMessage());
        } catch (Exception e) {
            log.error("修改信息发生异常：", e);
            resultDataStruct.setCode(500);
            resultDataStruct.setMessage(e.getMessage());
        }
        return resultDataStruct;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultMessageStruct updatePassword(SysUser sysUser) throws Exception {
        ResultMessageStruct resultMessageStruct = new ResultMessageStruct();

        if (sysUser.getPassword().length() > 16 || sysUser.getPassword().length() < 6)
            throw new CustomException(UserExceptionEnum.PASSWORD_LENGTH_LIMIT);
        if (isNumeric(sysUser.getPassword()) || !isContainNum(sysUser.getPassword()))
            throw new CustomException(UserExceptionEnum.PASSWORD_LENGTH_LIMIT);

        int i = userDao.updatePassword(sysUser);
        if (i > 0) {
            resultMessageStruct.setCode(200);
            resultMessageStruct.setMessage("修改成功");
        } else {
            resultMessageStruct.setCode(500);
            resultMessageStruct.setMessage("修改失败，请核对信息后重试");
        }
        return resultMessageStruct;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultMessageStruct updatePhone(SysUser sysUser) throws Exception {
        ResultMessageStruct resultMessageStruct = new ResultMessageStruct();

        int i = userDao.updatePhone(sysUser);
        if (i > 0) {
            resultMessageStruct.setCode(200);
            resultMessageStruct.setMessage("修改成功");
        } else {
            resultMessageStruct.setCode(500);
            resultMessageStruct.setMessage("修改失败，请核对信息后重试");
        }
        return resultMessageStruct;
    }

    @Override
    @FormatUrl(type = "after")
    public SysUser findByUserId(String userId) throws Exception {
        SysUser dbUser = userDao.findByUserId(userId);
        if (StringUtils.hasText(dbUser.getPhone()))
            dbUser.setPhone(AESUtil.decryptPhoneNumber(dbUser.getPhone()));

        // 如果头像信息为空，给到空符串
        if (StringUtils.isEmpty(dbUser.getAvatar()))
            dbUser.setAvatar("");
        return dbUser;
    }

    private String constructUsername() {
        IncrementSequence condition = new IncrementSequence();
        condition.setCategoryCode("user_account_seq");
        condition.setOptionCode("1");

        IncrementSequence incrementSequence = incrementSequenceService.getSingle(condition);
        String seq = incrementSequence.getOptionValue();

        Integer originValue = Integer.valueOf(incrementSequence.getOptionValue());
        originValue ++ ;

        String targetValue = originValue.toString();

        for (int i=0; i<(3-originValue.toString().length()); i++){
            targetValue = "0" + targetValue;
        }

        incrementSequence.setOptionValue(targetValue);

        incrementSequenceService.update(incrementSequence);

        StringBuilder usernameBuilder = new StringBuilder();
        usernameBuilder.append("小亿");
        usernameBuilder.append(seq);

        Random random = new Random();

        for (int i=0; i<2; i++) {
            usernameBuilder.append((char)(random.nextInt(26) + 64));
        }

        return usernameBuilder.toString();
    }

    /**
     * 判断是否全为数字
     *
     * @param str
     * @return
     */
    public static boolean isNumeric(String str){
        for (int i = str.length();--i>=0;){
            if (!Character.isDigit(str.charAt(i))){
                return false;
            }
        }
        return true;
    }

    /**
     * 判断是否包含数字
     *
     * @param content
     * @return
     */
    public static boolean isContainNum(String content) {
        boolean flag = false;
        Pattern p = Pattern.compile(".*\\d+.*");
        Matcher m = p.matcher(content);
        if (m.matches()) {
            flag = true;
        }
        return flag;
    }
}
